package service

import (
	"errors"
	"fmt"
	"net/url"
	"regexp"
	"strings"

	"gitee.com/sansaniot/ssiot-core/facade/env"
	"gitee.com/sansaniot/ssiot-core/httpmvc/service"
	"gitee.com/sansaniot/ssiot-core/logger"
	"github.com/gin-gonic/gin"
	"github.com/tidwall/sjson"
	"github.com/xuri/excelize/v2"
	"gorm.io/gorm"

	"ssdevice/common/constant"
	cDto "ssdevice/common/dto"
	"ssdevice/common/utils"
	"ssdevice/internal/device/models"
	"ssdevice/internal/device/models/command"
	"ssdevice/internal/device/models/query"
)

type Sensor struct {
	sysDevModel     *models.SysDev
	devProductModel *models.SysDevProduct
	devConfigModel  *models.SysDevConfig
	devSensorModel  *models.SysDevSensor
	service.Service
}

func (d *Sensor) SetDevModel(m *models.SysDev) *Sensor {
	d.sysDevModel = m
	return d
}

func (d *Sensor) SetProductModel(m *models.SysDevProduct) *Sensor {
	d.devProductModel = m
	return d
}

func (d *Sensor) SetConfigModel(m *models.SysDevConfig) *Sensor {
	d.devConfigModel = m
	return d
}

func (d *Sensor) SetSensorModel(m *models.SysDevSensor) *Sensor {
	d.devSensorModel = m
	return d
}

func (d *Sensor) SetAllModel() {
	d.sysDevModel = &models.SysDev{}
	d.devProductModel = &models.SysDevProduct{}
	d.devConfigModel = &models.SysDevConfig{}
	d.devSensorModel = &models.SysDevSensor{}
	d.sysDevModel.Orm = d.Orm
	d.devProductModel.Orm = d.Orm
	d.devConfigModel.Orm = d.Orm
	d.devSensorModel.Orm = d.Orm
}

// 添加变量
func (d *Sensor) AddSensor(req *command.SensorInsertReq) (err error, devSensor models.SysDevSensor) {
	err = d.Orm.Transaction(func(tx *gorm.DB) error {
		// 事务orm
		d.devSensorModel.Orm = tx
		if len(req.Id) == 0 {
			// 添加根变量
			if err = preValid(req.Key, req.Sn, req.ProductModel, req.UserId, true); err != nil {
				return err
			}
			req.Generate(&devSensor)
			// 添加变量
			if err = d.devSensorModel.Add(&devSensor); err != nil {
				return err
			}
		} else {
			// 子节点新增
			if err = preValid("", req.Sn, req.ProductModel, req.UserId, false); err != nil {
				return err
			}
			if err = d.addChildSensor(req, &devSensor); err != nil {
				return err
			}
			// 更新
			if err = d.devSensorModel.Mod(devSensor); err != nil {
				return err
			}
		}
		// 更新config
		if err = devSensorProfile(tx, devSensor); err != nil {
			return err
		}
		// 设备sensor缓存
		if len(devSensor.Sn) > 0 {
			var tmpMap map[string]interface{}
			if value, ok := constant.SensorCache.Get(devSensor.Sn); !ok {
				tmpMap = utils.BytesToMap(devSensor.Data)
			} else {
				// 合并
				tmpMap = value
				utils.DeepMerge(utils.BytesToMap(devSensor.Data), tmpMap)
			}
			// 再缓存
			constant.SensorCache.Set(devSensor.Sn, tmpMap)
		}
		return nil
	})
	return
}

func (d *Sensor) addChildSensor(req *command.SensorInsertReq, devSensor *models.SysDevSensor) (err error) {
	keySplit := strings.Split(req.Key, ".")
	if len(keySplit) <= 1 {
		return errors.New("未指定节点路径")
	}
	rootKey := keySplit[0]
	if err = d.devSensorModel.FindOne(devSensor, cDto.MakeCondition(query.SysDevSensorQuery{Id: req.Id, Key: rootKey})); err != nil {
		return
	}
	//data
	childData := map[string]interface{}{req.Key: req.Data}
	// 还原层级
	childData = utils.FixJsonKeyDot(childData)
	data := utils.BytesToMap(devSensor.Data)
	// 合并data
	utils.DeepMerge(childData, data)
	devSensor.Data = utils.MapToBytes(data)
	//config
	var childConfig map[string]interface{}
	if req.Config != nil {
		childConfig = map[string]interface{}{req.Key: *req.Config}
		childConfig = utils.FixJsonKeyDot(childConfig)
	} else {
		childConfig = utils.GetObjectConfig(childData)
	}
	config := utils.BytesToMap(devSensor.Config)
	// 合并config
	utils.DeepMerge(childConfig, config)
	devSensor.Config = utils.MapToBytes(config)
	// schema
	childSchema := utils.GetObjectSchema(childData)["properties"].(map[string]interface{})
	childTitle := utils.If(len(req.Label) > 0, req.Label, "").(string)
	childSchemaStr := string(utils.MapToBytes(childSchema))
	p := strings.ReplaceAll(req.Key, ".", ".properties.")
	childSchemaStr, _ = sjson.Set(childSchemaStr, p+".title", childTitle)
	childSchema = utils.BytesToMap([]byte(childSchemaStr))
	schema := utils.BytesToMap(devSensor.Schema)
	// 合并schema
	utils.DeepMerge(childSchema, schema)
	devSensor.Schema = utils.MapToBytes(schema)
	return
}

// 编辑变量
func (d *Sensor) ModSensor(req *command.SensorEditReq) (err error) {
	keySplit := strings.Split(req.Key, ".")
	rootKey := keySplit[0]
	cond := cDto.MakeCondition(query.SysDevSensorQuery{Id: req.Id, Key: rootKey})
	if err = d.devSensorModel.FindOne(d.devSensorModel, cond); err != nil {
		return
	}
	if len(keySplit) <= 1 {
		// 编辑根变量
		req.Generate(d.devSensorModel)
		if err = preValid(req.Key, d.devSensorModel.Sn, d.devSensorModel.ProductModel, req.UserId, req.Key != d.devSensorModel.Key); err != nil {
			return
		}
	} else {
		// 编辑子节点
		if err = preValid("", d.devSensorModel.Sn, d.devSensorModel.ProductModel, req.UserId, false); err != nil {
			return
		}
		editChildSensor(req, d.devSensorModel)
	}
	err = d.Orm.Transaction(func(tx *gorm.DB) error {
		d.devSensorModel.Orm = tx
		// 更新根变量
		if err = d.devSensorModel.Mod(d.devSensorModel); err != nil {
			return err
		}
		// 更新config
		if err = devSensorProfile(tx, *d.devSensorModel, req.ConfDel); err != nil {
			return err
		}
		// 设备sensor缓存
		if len(d.devSensorModel.Sn) > 0 {
			var tmpMap map[string]interface{}
			if value, ok := constant.SensorCache.Get(d.devSensorModel.Sn); !ok {
				tmpMap = utils.BytesToMap(d.devSensorModel.Data)
			} else {
				// 合并
				tmpMap = value
				utils.DeepMerge(utils.BytesToMap(d.devSensorModel.Data), tmpMap)
			}
			// 再缓存
			constant.SensorCache.Set(d.devSensorModel.Sn, tmpMap)
		}
		return nil
	})
	return
}

func editChildSensor(req *command.SensorEditReq, devSensor *models.SysDevSensor) {
	if len(req.ConfDel) > 0 {
		configStr := string(devSensor.Config)
		configStr, _ = sjson.Delete(configStr, req.ConfDel)
		devSensor.Config = []byte(configStr)
		// configDel单独传参
		return
	}
	if req.Data != nil {
		//data
		childData := map[string]interface{}{req.Key: req.Data}
		// 还原层级
		childData = utils.FixJsonKeyDot(childData)
		// 覆盖子节点data
		dataStr := string(devSensor.Data)
		dataStr, _ = sjson.Delete(dataStr, req.Key)
		dataStr, _ = sjson.Set(dataStr, req.Key, req.Data)
		devSensor.Data = []byte(dataStr)
		// schema
		childSchema := utils.GetObjectSchema(childData)["properties"].(map[string]interface{})
		childSchemaStr := string(utils.MapToBytes(childSchema))
		p := strings.ReplaceAll(req.Key, ".", ".properties.")
		if len(req.Label) > 0 {
			childSchemaStr, _ = sjson.Set(childSchemaStr, p+".title", req.Label)
		}
		childSchema = utils.BytesToMap([]byte(childSchemaStr))
		childSchemaData := utils.GetFieldFromJson(strings.Split(p, "."), childSchema)
		// 覆盖子节点schema
		schemaStr := string(devSensor.Schema)
		schemaStr, _ = sjson.Delete(schemaStr, p)
		schemaStr, _ = sjson.Set(schemaStr, p, childSchemaData)
		devSensor.Schema = []byte(schemaStr)
		if len(devSensor.Sn) > 0 {
			tmpMap := make(map[string]interface{})
			if value, ok := constant.SensorCache.Get(devSensor.Sn); ok {
				if err := utils.GobDeepCopy(value, &tmpMap); err != nil {
					logger.Error(err)
				} else {
					tmpStr := string(utils.MapToBytes(tmpMap))
					tmpStr, _ = sjson.Delete(tmpStr, req.Key)
					constant.SensorCache.Set(devSensor.Sn, utils.BytesToMap([]byte(tmpStr)))
				}
			}
		}
	} else {
		schemaStr := string(devSensor.Schema)
		if len(req.Label) > 0 {
			p := strings.ReplaceAll(req.Key, ".", ".properties.")
			schemaStr, _ = sjson.Set(schemaStr, p+".title", req.Label)
			devSensor.Schema = []byte(schemaStr)
		}
		if len(req.Type) > 0 {
			p := strings.ReplaceAll(req.Key, ".", ".properties.")
			schemaStr, _ = sjson.Set(schemaStr, p+".type", req.Type)
			devSensor.Schema = []byte(schemaStr)
		}
	}

	if req.Config != nil {
		//config
		childConfig := map[string]interface{}{req.Key: *req.Config}
		childConfig = utils.FixJsonKeyDot(childConfig)
		// 覆盖子节点config
		configStr := string(devSensor.Config)
		configStr, _ = sjson.Delete(configStr, req.Key)
		configStr, _ = sjson.Set(configStr, req.Key, *req.Config)
		devSensor.Config = []byte(configStr)
	}
}

func preValid(key, sn, productModeL, userId string, validKey bool) (err error) {
	// 修改key 校验重复性
	if validKey {
		if mc, _ := regexp.MatchString(".*[{}\\[\\]\\\\.\\-,?*^~@#$%&、\\s!>=<()+`/'\"]+.*", key); mc {
			return errors.New("变量标识符非法")
		}
		var count int64
		sensorM := &models.SysDevSensor{}
		sensorM.Orm = env.Db
		if err = sensorM.FindCount(sensorM, &count, cDto.MakeCondition(query.SysDevSensorQuery{Sn: sn, ProductModel: productModeL, Key: key})); err != nil {
			return
		}
		if count > 0 {
			return errors.New("变量key不可重复")
		}
	}
	// 校验操作权限
	deptId := ""
	if len(sn) > 0 {
		devModel := &models.SysDev{}
		devModel.Orm = env.Db
		if err = devModel.FindOne(devModel, cDto.MakeCondition(query.SysDevQuery{Sn: sn})); err != nil {
			return
		}
		deptId = devModel.DeptId
	} else if len(productModeL) > 0 {
		productM := &models.SysDevProduct{}
		productM.Orm = env.Db
		if err = productM.FindOne(productM, cDto.MakeCondition(query.SysProductQuery{ProductModel: productModeL})); err != nil {
			return
		}
		deptId = productM.DeptId
	} else {
		err = errors.New("未指定设备/产品参数")
		return
	}
	if deptId == constant.PublicGroupId && userId != "1" {
		err = errors.New("没权限操作公共分组资源")
	}
	return
}

// 删除变量
func (d *Sensor) DeleteSensor(req *command.SensorDeleteReq) (err error) {
	delIds := strings.Split(strings.ReplaceAll(req.Id, " ", ""), ",")
	sensorList := make([]models.SysDevSensor, 0)
	cond := cDto.MakeCondition(query.SysDevSensorQuery{IdIn: delIds})
	if err = d.devSensorModel.FindList(&sensorList, cond); err != nil {
		return
	}
	keySplit := strings.Split(req.Key, ".")
	if len(req.Key) == 0 || len(keySplit) <= 1 {
		// 删除根节点
		err = d.Orm.Transaction(func(tx *gorm.DB) error {
			// 事务orm
			d.devSensorModel.Orm = tx
			d.devConfigModel.Orm = tx
			// 删sensor
			if err = d.devSensorModel.Delete(d.devSensorModel, cond); err != nil {
				return err
			}
			// 更新config
			if err = deleteSensorProfile(tx, sensorList); err != nil {
				return err
			}
			// 删除变量删缓存(若再次上报 页面会再显示)
			deleteDevSensorCache(sensorList)
			return nil
		})
	} else {
		// 删除子节点
		if len(sensorList) == 0 {
			return
		}
		devSensor := sensorList[0]
		dataStr := string(devSensor.Data)
		dataStr, _ = sjson.Delete(dataStr, req.Key)
		devSensor.Data = []byte(dataStr)
		schemaStr := string(devSensor.Schema)
		p := strings.ReplaceAll(req.Key, ".", ".properties.")
		schemaStr, _ = sjson.Delete(schemaStr, p)
		devSensor.Schema = []byte(schemaStr)
		configStr := string(devSensor.Config)
		configStr, _ = sjson.Delete(configStr, req.Key)
		devSensor.Config = []byte(configStr)
		err = d.Orm.Transaction(func(tx *gorm.DB) error {
			d.devSensorModel.Orm = tx
			// 更新根变量
			if err = d.devSensorModel.Mod(&devSensor); err != nil {
				return err
			}
			// 更新config
			if err = devSensorProfile(tx, devSensor); err != nil {
				return err
			}
			// 设备sensor缓存
			if len(devSensor.Sn) > 0 {
				tmpMap := make(map[string]interface{})
				if value, ok := constant.SensorCache.Get(devSensor.Sn); ok {
					if err = utils.GobDeepCopy(value, &tmpMap); err != nil {
						logger.Error(err)
					} else {
						tmpStr := string(utils.MapToBytes(tmpMap))
						tmpStr, _ = sjson.Delete(tmpStr, req.Key)
						constant.SensorCache.Set(devSensor.Sn, utils.BytesToMap([]byte(tmpStr)))
					}
				}
			}
			return nil
		})
	}
	return
}

// 导出变量
func (d *Sensor) ExportSensor(c *gin.Context, req *query.SysDevSensorQuery) error {
	req.PageIndex = 0
	protoSensors, err := d.devSensorModel.FindProtocolSensorList(req)
	if err != nil {
		return err
	}
	if len(protoSensors) == 0 {
		return errors.New("查无数据")
	}
	// 生成模板
	f := excelize.NewFile()
	defer f.Close()
	// 模板内容
	if err = FillExportVariable(f, protoSensors); err != nil {
		return err
	}
	// 删除excelize的默认sheet
	f.DeleteSheet("Sheet1")
	// 响应文件流
	fileName := fmt.Sprintf("设备变量.xlsx")
	c.Header("Content-Disposition", fmt.Sprintf("attachment; filename*=utf-8''%s", url.QueryEscape(fileName)))
	c.Header("File-Name", url.QueryEscape(fileName))
	c.Header("Content-Type", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet;charset=UTF-8")
	if _, err := f.WriteTo(c.Writer); err != nil {
		_, _ = fmt.Fprintf(c.Writer, err.Error())
		return err
	}
	return nil
}

// 导入变量
func (d *Sensor) ImportSensor(c *gin.Context, req *query.SysDevSensorQuery) error {
	// 获取文件对象
	file, header, err := c.Request.FormFile("file")
	if err != nil {
		return err
	}
	if file == nil || !strings.HasSuffix(header.Filename, ".xlsx") {
		return errors.New("非法文件，请使用正确的文件导入")
	}
	defer file.Close()
	f, err := excelize.OpenReader(file)
	if err != nil {
		return err
	}
	// 执行导入
	if err = ImportVariableData(d.devSensorModel, f, req.UserId); err != nil {
		return err
	}
	return nil
}
